﻿using ArtMath.Attribute;
using ArtMath.Component.Interface;
using ArtMath.Core.Data;
using ArtMath.Data;
using ArtMath.PointCollection;
using ArtMath.PointCollection.Helper;
using ArtMath.Setting;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using ArtMath.CommonType;

namespace ArtMath.Component.Line
{
    /// <summary>
    /// 参数方程
    /// </summary>
    [Serializable]
    public class ParametricEquation : LineBase, ICurve
    {
        CurveDescribable ske = new CurveDescribable(), pske = new CurveDescribable();
        List<Curve> curs = new List<Curve>(), pcurs = new List<Curve>();
        PadStringX x, y;
        bool add, breaked = true;
        public ParametricEquation(SketchPad pad, string name, string x, string y, bool addToList = true) : base(pad, name, ToolTypeName.csfc, addToList)
        {
            ske.Curves = curs;
            pske.Curves = pcurs;
            LineColor = Settings.Instance.FunctionColor;
            Abscissa = new PadStringX(Pad, x);
            Ordinate = new PadStringX(Pad, y);
        }
        public void ClearImage()
        {
            curs.Clear();
            pcurs.Clear();
            add = false;
            breaked = true;
        }
        public override PointCollectionsManager Skeleton
        {
            get
            {
                return new PointCollectionsManager(ske);
            }
        }
        public override PointCollectionsManager PSkeleton
        {
            get
            {
                return new PointCollectionsManager(pske);
            }
        }
        public override PointCollectionsManager NewSkeleton
        {
            get
            {
                return new PointCollectionsManager(ske);
            }
        }
        public override PointCollectionsManager NewPSkeleton
        {
            get
            {
                return new PointCollectionsManager(pske);
            }
        }
        void ParametersValueChanged(DocStringX sender, ParametersValueChangedEventArgs e)
        {
            if (add)
            {
                if (breaked)
                {
                    curs.Add(new LengthCurve());
                    pcurs.Add(new Curve());
                    breaked = false;
                }
                PointD xy = new PointD(x.Value, y.Value), pxy = Pad.MathToPxy(xy);
                if (xy.IsNumberPoint)
                {
                    curs[curs.Count - 1].Add(xy);
                    if (pxy.IsPaintable)
                    {
                        pcurs[pcurs.Count - 1].Add(pxy);
                    }
                    else
                    {
                        breaked = true;
                    }
                }
                else
                {
                    breaked = true;
                }
            }
            add = !add;
        }

        [MultilingualCategory("Structure"), MultilingualDisplayName("Abscissa")]
        public PadStringX Abscissa
        {
            get { return x; }
            set
            {
                if (x is object)
                {
                    x.ParametersValueChanged -= ParametersValueChanged;
                }
                x = value;
                if (x is object)
                {
                    x.ParametersValueChanged += ParametersValueChanged;
                }
            }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("Ordinate")]
        public PadStringX Ordinate
        {
            get { return y; }
            set
            {
                if (y is object)
                {
                    y.ParametersValueChanged -= ParametersValueChanged;
                }
                y = value;
                if (y is object)
                {
                    y.ParametersValueChanged += ParametersValueChanged;
                }
            }
        }
        [Browsable(false)]
        public override string Formula
        {
            get
            {
                return base.Formula;
            }
        }
        [Browsable(false)]
        public override AngleStringX RotateAngle
        {
            get
            {
                return base.RotateAngle;
            }

            set
            {
                base.RotateAngle = value;
            }
        }
        [Browsable(false)]
        public override RPointS RotateCenter
        {
            get
            {
                return base.RotateCenter;
            }

            set
            {
                base.RotateCenter = value;
            }
        }
        [Browsable(false)]
        public override PropertyDisplayer FormulaDisplayer
        {
            get
            {
                return base.FormulaDisplayer;
            }

            set
            {
                base.FormulaDisplayer = value;
            }
        }
        [Browsable(false)]
        public PadStringX Accuracy
        {
            get
            {
                throw new NotImplementedException();
            }

            set
            {
                throw new NotImplementedException();
            }
        }
        public override void Relocate(PointsRelocationReason reason)
        {
            BuildSamples();
            base.Relocate(reason);
        }
        public override void CheckInRegion(RectangleD rect)
        {
            SetInPicker(rect.IntersectCurves(pcurs));
            base.CheckInRegion(rect);
        }
        //public override PointD SlideDestination(PointD currentLocation, double length, out bool reverse)
        //{
        //    if (Settings.Instance.AnimateOnOneSectionOfFunction)
        //    {
        //        int curveIndex, pointIndex;
        //        currentLocation.GetCurveIndexAndPointIndex(curs, out curveIndex, out pointIndex);
        //        return curs[curveIndex].SlideDestination(currentLocation, length, out reverse);
        //    }
        //    return ske.SlideDestination(currentLocation, length, out reverse);//使用NewSkeleton可能会降低性能
        //}
        public override void Paint(Graphics gra)
        {
            if (ObjectState == ObjectState.Normal && Visible)
            {
                foreach (Curve item in pcurs)
                {
                    item.Paint(gra, LinePen);
                }
            }
        }

        public void BuildSamples()
        {
            pcurs.Clear();
            foreach (LengthCurve item in curs)
            {
                Curve pc = new Curve();
                foreach (PointD xy in item)
                {
                    PointD pxy = Pad.MathToPxy(xy);
                    if (pxy.IsPaintable)
                    {
                        pc.Add(pxy);
                    }
                }
                pcurs.Add(pc);
            }
        }

        public PointD[] GetTangentPoints(PointD passPoint)
        {
            return null;
        }

        public double? GetTangentLineSlope(PointD pt)
        {
            //Parameter[] paras = x.IncludedParameters.Intersect(y.IncludedParameters).ToArray();
            //if (paras?.Length == 1)
            //{
            //    string deri = $"({Derivation.GetDerivation(y.Expression, paras[0].Name)})/({Derivation.GetDerivation(x.Expression, paras[0].Name)})";
            //    foreach (Parameter item in x.IncludedParameters)
            //    {
            //        if (item == paras[0]) continue;
            //        deri = Regex.Replace(deri, $"\\b{item.Name}\\b", $"({item.Value})");
            //    }
            //    foreach (Parameter item in y.IncludedParameters)
            //    {
            //        if (item == paras[0]) continue;
            //        deri = Regex.Replace(deri, $"\\b{item.Name}\\b", $"({item.Value})");
            //    }
            //    try
            //    {
            //        return Calculation.Calculate(Regex.Replace(deri, $"\\b{paras[0].Name}\\b", "(?)"));//这里需要根据点坐标求参数值！！
            //    }
            //    catch (Exception)
            //    {
            //    }
            //}
            //else
            //{
            return curs.GetGeneralCurveTangentLineSlope(pt);
        }
    }
}
